﻿/* 
 * Copyright (c) 2011-12 Andrey Bulygin
 * 
 * This file is part of Interceptor.
 * Interceptor is free software: you can redistribute it and/or modify it under the terms of the GNU 
 * Library General Public License as published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * Interceptor is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 
 * the GNU Library General Public License for more details. You should have received a copy of the GNU 
 * Library General Public License along with Interceptor. If not, write to the Free Software Foundation, Inc., 59 
 * Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Interceptor.Core.Objects
{
	internal class ItcMethodDefinition
	{
		static int CONTEXT_INVOKER_PARAM_INDEX = 1;

		public MethodInfo Method { get; set; }
		public Type ReturnType { get; set; }
		public Type TargetType { get; set; }
		public Type ContextDelegateType { get; set; }
		public ItcParameterDefinition[] Parameters { get; set; }
		public ItcType InterceptorType { get; set; }

		public ItcMethodDefinition(MethodInfo method)
		{
			Method = method;
			TargetType = method.GetParameters()[0].ParameterType;
			ReturnType = method.ReturnType;
			Parameters = method.GetParameters().Skip(2).Select(x => new ItcParameterDefinition(x)).ToArray();
			InterceptorType = ExtractInterceptorTypeFromMethod(method);
			ContextDelegateType = ExtractContextDelegateType(method, InterceptorType);
		}
		private static Type ExtractContextDelegateType(MethodInfo interceptorMethod, ItcType itcType)
		{
			var parameter = interceptorMethod.GetParameters()[CONTEXT_INVOKER_PARAM_INDEX];
			if (itcType == ItcType.Delegate)
				return parameter.ParameterType;
			if (itcType == ItcType.Invoker)
				return parameter.ParameterType.GetGenericArguments()[0];

			throw new InvalidOperationException();
		}
		private static ItcType ExtractInterceptorTypeFromMethod(MethodInfo interceptorMethod)
		{
			var parameter = interceptorMethod.GetParameters()[CONTEXT_INVOKER_PARAM_INDEX];
			if (parameter.ParameterType.IsSubclassOf(typeof(Delegate)))
				return ItcType.Delegate;
			if (parameter.ParameterType.IsGenericType)
			{
				if (parameter.ParameterType.GetGenericTypeDefinition() == typeof(Invoker<>))
					return ItcType.Invoker;
			}
			throw new InvalidOperationException();
		}
		
	}
}
